import { ascendingSort, randomInteger } from "../";

/**
 * Check whether the number is a percentage.
 * @param num The number to check.
 * @return Return true if the number is a percentage.
 */
export function checkPercent(num: number): boolean {
  if (num > 1 || num < 0) {
    return false;
  } else {
    return true;
  }
}

/**
 * Percentage-Driven random event trigger.
 * @param data The event and chance data.
 * @return A boolean of whether the event will be triggered.
 */
export function withPercentChance(data: PercentChanceData): boolean {
  if (!checkPercent(data.chance)) {
    throw new RangeError("The value is not a percentage!");
  }
  if (randomInteger(100, 1) <= data.chance * 100) {
    if (data.event) {
      data.event();
    }
    return true;
  } else {
    return false;
  }
}

/**
 * Weight-Driven random event trigger.
 * @param data The event and weight data.
 * @return The Trigger result.
 */
export function withWeightChance(data: WeightChanceData[]): WeightChanceResult {
  let weightArr: number[] = [];
  data.forEach((data) => {
    weightArr.push(data.weight);
  });
  const totalWeight = data.reduce(
    (accumulator, currentValue) => accumulator + currentValue.weight,
    0
  );
  let random = randomInteger(totalWeight, 1);
  weightArr.push(random);
  ascendingSort(weightArr);
  let index = weightArr.indexOf(random);
  if (data[index].event) {
    data[index].event();
  }
  return {
    weightSum: totalWeight,
    weightRand: random,
    dataIndex: index,
  };
}

/**
 * The event and weight data for {@link withWeightChance}.
 */
export interface WeightChanceData {
  /**
   * The weight to teigger the event.
   */
  weight: number;
  /**
   * The event.
   */
  event?: () => void;
}

/**
 * The event and chance data for {@link withPercentChance}.
 */
export interface PercentChanceData {
  /**
   * The trigger probability, should be a percentage (0~1).
   */
  chance: number;
  /**
   * The event.
   */
  event?: () => void;
}

/**
 * The Trigger result for {@link withWeightChance}.
 */
export interface WeightChanceResult {
  /**
   * Sum of weights.
   */
  weightSum: number;
  /**
   * Random generated weight random number
   */
  weightRand: number;
  /**
   * Index of Triggered data.
   */
  dataIndex: number;
}
